package com.zxbg.service.impl.systemtoolsServiceImpl;

import com.zxbg.dao.DepartmentDao;
import com.zxbg.dao.EmployeeDao;
import com.zxbg.domain.Department;
import com.zxbg.domain.Employee;
import com.zxbg.service.systemtoolsService.OrganizationalStructureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@Service
public class OrganizationalStructureServiceImpl implements OrganizationalStructureService {
    @Autowired
    DepartmentDao departmentDao;
    @Autowired
    EmployeeDao employeeDao;

    @Override
    public Department getRootNode(Integer tenant_id) {
        Department resDept =  departmentDao.getRootNode(tenant_id);
        resDept.setLeaf(false);
        resDept.setDept_header(getDeptSetHeaders(resDept, tenant_id));
        return resDept;
    }

    @Override
    public List<Department> getDepartmentByParentDeptId(Integer parent, Integer tenant_id) {
        List<Department> resDeptList = departmentDao.getDepartmentByParentDeptId(parent, tenant_id);
        for (int i = 0; i < resDeptList.size(); i++) {
            Department temp = resDeptList.get(i);
            temp.setLeaf(temp.getChildren_dept_id() == null || temp.getChildren_dept_id().equals("") ? true : false);
            temp.setDept_header(getDeptSetHeaders(temp, tenant_id));
        }
        return resDeptList;
    }

    public List<Employee> getDeptSetHeaders(Department department, Integer tenant_id) {
        String[] header_ids = department.getDept_head() == null || department.getDept_head().equals("") ? new String[0] : department.getDept_head().split(",");
        List<Employee> employeeList = new ArrayList<>();
        for (int j = 0; j < header_ids.length; j++) {
            employeeList.add(employeeDao.getEmployeeByEmployeeId(header_ids[j], tenant_id));
        }
        return employeeList;
    }

    @Override
    public List<Employee> getEmployeesByWorkerId(Map<String, Object> search_info, Integer tenant_id) {
        String employeeIds = (String) search_info.get("worker_id");
        Integer status = (Integer) search_info.get("status");
        String[] employeeList = employeeIds.split(",");
        List<Employee> resList = new ArrayList<>();
        for (int i = 0; i < employeeList.length; i++) {
            Employee temp = employeeDao.getEmployeeByEmployeeId(employeeList[i], tenant_id);
            if(temp.getStatus() == status) {
                resList.add(getAllKindsDept(temp));
            }
        }
        return resList;
    }

    public Employee getAllKindsDept(Employee employee) {
        String allDeptId = employee.getAll_dept_id();
        String[] deptIds = allDeptId.split(",");
        List<Department> departmentList = new ArrayList<>();
        for (int j = 0; j < deptIds.length; j++) {
            Department tempDept = departmentDao.getDeptById(Integer.parseInt(deptIds[j]));
            departmentList.add(tempDept);
        }
        if(departmentList.get(0) != null) {
            employee.setAll_department(departmentList);
        }
        String[] respDept = employee.getResponsible_dept_id() == null || employee.getResponsible_dept_id().equals("") ? new String[0] : employee.getResponsible_dept_id().split(",");
        List<Department> departmentList1 = new ArrayList<>();
        for (int j = 0; j < respDept.length; j++) {
            Department tempDept = departmentDao.getDeptById(Integer.parseInt(respDept[j]));
            departmentList1.add(tempDept);
        }
        if(departmentList1.size() > 0 && departmentList1.get(0) != null) {
            employee.setResponsible_dept(departmentList1);
        }
        return employee;
    }

    @Override
    public String addEmployee(Employee employee, Integer tenant_id) {
        if(employeeDao.getEmployeeByWorkId(employee.getWork_id(), tenant_id) != null) {
            return "工号不可重复";
        }
        if(employeeDao.getEmployeeByEmployeeId(employee.getEmployee_id(), tenant_id) != null) {
            return "账号不可重复";
        }
        employee.setLogin_password(DigestUtils.md5DigestAsHex(employee.getLogin_password().getBytes()));
        employee.setTenant_id(tenant_id);
        employeeDao.addEmployee(employee);
        String[] dept_ids = employee.getAll_dept_id().split(",");
        String[] dept_headers = employee.getResponsible_dept_id() == null ? new String[0] : employee.getResponsible_dept_id().split(",");
        for (int i = 0; i < dept_ids.length; i++) {
            setNewWorkerId(Integer.parseInt(dept_ids[i]), employee.getEmployee_id());
        }
        for (int i = 0; i < dept_headers.length; i++) {
            setNewDeptHeaders(Integer.parseInt(dept_headers[i]), employee);
        }
        return "";
    }

    public void setNewWorkerId(Integer dept_id, String new_worker_id) {
        Department temp_dept = departmentDao.getDeptById(dept_id);
        String[] cws = temp_dept.getWorker_id() != null ? temp_dept.getWorker_id().split(",") : new String[0];
        if(!Arrays.asList(cws).contains(new_worker_id)) {
            String change_worker = temp_dept.getWorker_id() != null && !temp_dept.getWorker_id().equals("") ? temp_dept.getWorker_id() + ',' + new_worker_id : new_worker_id;
            departmentDao.setWorkerIdByDeptId(dept_id, change_worker);
        }
        if(temp_dept.getParent() != null) {
            setNewWorkerId(temp_dept.getParent(), new_worker_id);
        }
    }

    public void setNewDeptHeaders(Integer dept_id, Employee employee) {
        Department temp_dept = departmentDao.getDeptById(dept_id);
        String[] headers = temp_dept.getDept_head() == null || temp_dept.getDept_head().equals("") ? new String[0] : temp_dept.getDept_head().split(",");
        if(!Arrays.asList(headers).contains(employee.getEmployee_id())) {
            String change_header = temp_dept.getDept_head() + ',' + employee.getEmployee_id();
            departmentDao.setDeptHeadByDeptId(dept_id, change_header);
        }
    }

    @Override
    public String updateEmployee(Employee employee, Integer tenant_id) {
        Employee searchRes = employeeDao.getEmployeeByWorkId(employee.getWork_id(), tenant_id);
        if(searchRes != null && !searchRes.getEmployee_id().equals(employee.getEmployee_id())) {
            return "工号不可重复";
        }
        try {
            String[] different = getDifferent(employee, tenant_id);
            String[] useless = new String[]{"tenant_id", "login_password", "responsible_dept", "all_department"};
            for (int i = 0; i < different.length; i++) {
                if(different[i] != null && !Arrays.asList(useless).contains(different[i])) {
                    // System.out.println(different[i]);
                    Method method = employee.getClass().getMethod("get" + different[i].substring(0, 1).toUpperCase() + different[i].substring(1));
                    Object newValue = method.invoke(employee);
                    if(different[i] == "all_dept_id" || different[i] == "responsible_dept_id") {
                        String[] new_dept_id = ((String) method.invoke(employee)).split(",");
                        String[] old_dept_id = null;
                        if(different[i] == "all_dept_id") {
                            old_dept_id = employeeDao.getEmployeeByEmployeeId(employee.getEmployee_id(), tenant_id).getAll_dept_id().split(",");
                        } else {
                            old_dept_id = employeeDao.getEmployeeByEmployeeId(employee.getEmployee_id(), tenant_id).getResponsible_dept_id().split(",");
                        }
                        for (int j = 0; j < new_dept_id.length; j++) {
                            if(!Arrays.asList(old_dept_id).contains(new_dept_id[j])) {
                                if(different[i] == "all_dept_id") {
                                    setNewWorkerId(Integer.parseInt(new_dept_id[j]), employee.getEmployee_id());
                                } else {
                                    setNewDeptHeaders(Integer.parseInt(new_dept_id[j]), employee);
                                }
                            }
                        }
                        for (int j = 0; j < old_dept_id.length; j++) {
                            if(!Arrays.asList(new_dept_id).contains(old_dept_id[j])) {
                                if(different[i] == "all_dept_id") {
                                    deleteWorkerId(Integer.parseInt(old_dept_id[j]), employee.getEmployee_id(), new_dept_id);
                                } else {
                                    deleteHeader(Integer.parseInt(old_dept_id[j]), employee.getEmployee_id());
                                }
                            }
                        }
                    }
                    String resSValue = null;
                    Integer resIValue = null;
                    try {
                        resIValue = Integer.parseInt(String.valueOf(newValue));
                        employeeDao.updateSomeIByEmployeeId(employee.getEmployee_id(), different[i], resIValue, tenant_id);
                    } catch (Exception e) {
                        resSValue = (String) newValue;
                        employeeDao.updateSomeVByEmployeeId(employee.getEmployee_id(), different[i], resSValue, tenant_id);
                    }
                }
            }
        } catch (Exception e) {
            return e.toString();
        }
        return "";
    }

    public void deleteWorkerId(Integer dept_id, String employee_id, String[] new_all_dept_id) {
        Department department = departmentDao.getDeptById(dept_id);
        String[] worker_ids =  department.getWorker_id().split(",");
        if(!Arrays.asList(new_all_dept_id).contains(String.valueOf(dept_id)) && !getAllChildrenIfHasTargets(department, new_all_dept_id)) {
            List<String> new_workers = new ArrayList<>();
            for (int i = 0; i < worker_ids.length; i++) {
                if(!worker_ids[i].equals(employee_id)) {
                    new_workers.add(worker_ids[i]);
                }
            }
            String res_worker = String.join(",", new_workers);
            departmentDao.setWorkerIdByDeptId(dept_id, res_worker);
            if(department.getParent() != null && !department.getParent().equals("")) {
                deleteWorkerId(department.getParent(), employee_id, new_all_dept_id);
            }
        }
    }

    public void deleteHeader(Integer dept_id, String employee_id) {
        Department temp_dept = departmentDao.getDeptById(dept_id);
        String[] headers = temp_dept.getDept_head() == null || temp_dept.getDept_head().equals("") ? new String[0] : temp_dept.getDept_head().split(",");
        String resDeptHead = "";
        for (int i = 0; i < headers.length; i++) {
            if(!headers[i].equals(employee_id)) {
                resDeptHead = resDeptHead.equals("") ? headers[i] : resDeptHead + headers[i];
            }
        }
        departmentDao.setDeptHeadByDeptId(dept_id, resDeptHead);
    }

    public boolean getAllChildrenIfHasTargets(Department department, String[] targets) {
        String childrenDeptIds = department.getChildren_dept_id();
        if(childrenDeptIds == null || childrenDeptIds.equals("")) {
            return false;
        } else {
            boolean res = false;
            String[] ids = childrenDeptIds.split(",");
            for (int i = 0; i < ids.length; i++) {
                Department tempDept = departmentDao.getDeptById(Integer.parseInt(ids[i]));
                for (int j = 0; j < targets.length; j++) {
                    if(Arrays.asList(ids).contains(targets[j])) {
                        res = true;
                    } else {
                        res = getAllChildrenIfHasTargets(tempDept, targets);
                    }
                }
            }
            return res;
        }
    }

    public String[] getDifferent(Employee employee, Integer tenant_id) throws Exception {
        Employee currentEmployee = employeeDao.getEmployeeByEmployeeId(employee.getEmployee_id(), tenant_id);
        String[] filedName = getFiledName(employee);
        String[] res = new String[25];
        int ind = 0;
        for (int i = 0; i < filedName.length; i++) {
            Method method = employee.getClass().getMethod("get" + filedName[i].substring(0, 1).toUpperCase() + filedName[i].substring(1));
            Object currentValue = method.invoke(currentEmployee);
            Object changeValue = method.invoke(employee);
            if(currentValue == null || changeValue == null) {
                if(
                    (currentValue == null && changeValue == null) ||
                    (currentValue == null && changeValue == "") ||
                    (currentValue == "" && changeValue == null)
                ) {
                    continue;
                }
                res[ind++] = filedName[i];
            } else {
                if(!currentValue.equals(changeValue)) {
                    res[ind++] = filedName[i];
                }
            }
        }
        return res;
    }

    private static String[] getFiledName(Object o){
        Field[] fields=o.getClass().getDeclaredFields();
        String[] fieldNames=new String[fields.length];
        for(int i=0;i<fields.length;i++){
            fieldNames[i]=fields[i].getName();
        }
        return fieldNames;
    }

    @Override
    public boolean changeEmployeeStatus(List<String> employee_ids, Integer tenant_id, Integer status) {
        for (int i = 0; i < employee_ids.size(); i++) {
            if(employeeDao.changeEmployeeStatus(employee_ids.get(i), tenant_id, status) == 0) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean changePassword(String employee_id, String new_password, Integer tenant_id) {
        return employeeDao.changePassword(employee_id, DigestUtils.md5DigestAsHex(new_password.replace("\"", "").getBytes()), tenant_id) > 0;
    }

    @Override
    public String addSubDept(Integer dept_id, String add_dept, Integer tenant_id) {
        Department parentDept = departmentDao.getDeptById(dept_id);
        boolean ifHas = ifHasChildrenRepeat(parentDept, add_dept);
        if(ifHas) {
            return "已含有该子部门";
        }
        String parentChildString = parentDept.getChildren_dept_id();
        Department tempDept = new Department();
        Department lastOrderDept = departmentDao.getLastChildOrderDept(dept_id);
        Integer lastOrder = lastOrderDept == null ? 0 : lastOrderDept.getOrder();
        tempDept.setDept_name(add_dept);
        tempDept.setTenant_id(tenant_id);
        tempDept.setParent(dept_id);
        tempDept.setOrder(lastOrder + 1);
        if(departmentDao.addDepartment(tempDept) <= 0) {
            return "添加失败";
        }
        Department newDept = departmentDao.getNewDept();
        Integer newDeptId = newDept.getDept_id();
        parentDept.setChildren_dept_id(parentChildString == null ? String.valueOf(newDeptId) : parentChildString + "," + newDeptId);
        if(departmentDao.setChildDeptIdByDeptId(parentDept.getDept_id(), parentDept.getChildren_dept_id()) < 0) {
            return "添加失败";
        }
        return "";
    }

    public boolean ifHasChildrenRepeat(Department parentDept, String find_name) {
        String parentChildString = parentDept.getChildren_dept_id();
        if(parentChildString != null && !parentChildString.equals("")) {
            String[] child_dept_ids = parentChildString.split(",");
            for (int i = 0; i < child_dept_ids.length; i++) {
                if(departmentDao.getDeptById(Integer.parseInt(child_dept_ids[i])).getDept_name().equals(find_name)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public String changeDeptName(Integer dept_id, String new_name) {
        Department changeTarget = departmentDao.getDeptById(dept_id);
        boolean ifHas = ifHasChildrenRepeat(departmentDao.getDeptById(changeTarget.getParent()), new_name);
        if(ifHas) {
            return "已含有该子部门";
        }
        changeTarget.setDept_name(new_name);
        return departmentDao.setDeptNameByDeptId(changeTarget) > 0 ? "" : "修改失败";
    }

    @Override
    public boolean deleteDept(Integer dept_id) {
        Department willDelete = departmentDao.getDeptById(dept_id);
        String[] parentChildren = departmentDao.getDeptById(willDelete.getParent()).getChildren_dept_id().split(",");
        String newChildrenString = "";
        for (int i = 0; i < parentChildren.length; i++) {
            if(!parentChildren[i].equals(String.valueOf(dept_id))) {
                newChildrenString = newChildrenString.equals("") ? parentChildren[i] : newChildrenString + "," + parentChildren[i];
            }
        }
        departmentDao.setChildDeptIdByDeptId(willDelete.getParent(), newChildrenString);
        return departmentDao.deleteDept(dept_id) > 0;
    }

    @Override
    public boolean deptMove(Integer dept_id, Integer direction) {
        Department fromDept = departmentDao.getDeptById(dept_id);
        Department toDept = new Department();
        Department parentDept = departmentDao.getDeptById(fromDept.getParent());
        String[] parentChildrenDeptId = parentDept.getChildren_dept_id().split(",");
        for (int i = 0; i < parentChildrenDeptId.length; i++) {
            Department temp = departmentDao.getDeptById(Integer.parseInt(parentChildrenDeptId[i]));
            if(temp.getOrder() == fromDept.getOrder() + direction) {
                toDept = temp;
            }
        }
        fromDept.setOrder(toDept.getOrder());
        toDept.setOrder(toDept.getOrder() - direction);
        departmentDao.setDeptOrderByDeptId(fromDept);
        departmentDao.setDeptOrderByDeptId(toDept);
        return true;
    }

    @Override
    public boolean setDeptHeader(List<Employee> employeeList, Integer dept_id, Integer tenant_id) {
        List<String> newHeaders = new ArrayList<>();
        for (int i = 0; i < employeeList.size(); i++) {
            newHeaders.add(employeeList.get(i).getEmployee_id());
        }
        Department changeDept = departmentDao.getDeptById(dept_id);
        String headerString = changeDept.getDept_head();
        String[] oldHeaders = headerString == null || headerString.equals("") ? new String[0] : headerString.split(",");
        for (int i = 0; i < newHeaders.size(); i++) {
            if(!Arrays.asList(oldHeaders).contains(newHeaders.get(i))) {
                String employeeCurrentResponse = employeeDao.getEmployeeByEmployeeId(newHeaders.get(i), tenant_id).getResponsible_dept_id();
                if(employeeCurrentResponse == null || employeeCurrentResponse.equals("")) {
                    employeeDao.setResponseDeptByEmployeeId(newHeaders.get(i), String.valueOf(dept_id), tenant_id);
                } else {
                    String[] responses = employeeCurrentResponse.split(",");
                    boolean ifNeedAdd = true;
                    for (int j = 0; j < responses.length; j++) {
                        if(Integer.parseInt(responses[j]) == dept_id) {
                            ifNeedAdd = false;
                        }
                    }
                    if(ifNeedAdd) {
                        employeeDao.setResponseDeptByEmployeeId(newHeaders.get(i), employeeCurrentResponse + "," + dept_id, tenant_id);
                    }
                }
            }
        }
        for (int i = 0; i < oldHeaders.length; i++) {
            if(!newHeaders.contains(oldHeaders[i])) {
                String[] responses = employeeDao.getEmployeeByEmployeeId(oldHeaders[i], tenant_id).getResponsible_dept_id().split(",");
                String resResponseString = "";
                for (int j = 0; j < responses.length; j++) {
                    if(Integer.parseInt(responses[j]) != dept_id) {
                        resResponseString = resResponseString.equals("") ? responses[j] : resResponseString + "," + responses[j];
                    }
                }
                employeeDao.setResponseDeptByEmployeeId(oldHeaders[i], resResponseString, tenant_id);
            }
        }
        departmentDao.setDeptHeadByDeptId(dept_id, String.join(",", newHeaders));
        return true;
    }

    @Override
    public List<Department> searchDept(String key, Integer tenant_id) {
        return departmentDao.getDeptByNameKey("%" + key.replace("\"", "") + "%", tenant_id);
    }
}
